`include "define.v"

module ID (
    input rst,
    input [31:0]pc,
    input [31:0]inst,   // Instruction input 
    input [31:0]regaData_i, //Data input
    input [31:0]regbData_i,

    output reg[5:0]op,  // opOut
    output reg regaRd,  // reabOut
    output reg [4:0]regaAddr,
    output reg [31:0]regaData,
    output reg regbRd,  //regbOut
    output reg [4:0]regbAddr,
    output reg [31:0]regbData,
    output reg regcWr,  //regcOut
    output reg [4:0]regcAddr,
    output reg [31:0]jAddr, //jump instruction
    output reg jCe,
    output reg hiRd,
    output reg loRd
);

    wire[5:0] inst_op = inst[31:26];
    wire[5:0] func = inst[5:0];
    reg[31:0] imm;
    wire[31:0] npc = pc + 4;

    always@(*)begin // Instruction Tramsmition
        jAddr = `Zero;
        jCe = `Invalid;
        if(rst == `Enable) // Can't read Instructions
        begin
            op = `Zero;
            regaRd = `Invalid;
            regaAddr = `Zero;
            regbRd = `Invalid;
            regbAddr = `Zero;
            regcWr = `Invalid;
            regcAddr = `Zero;
            //jAddr = `Zero;
            //jCe = `Invalid;
            imm =  `Zero;
			hiRd = `Invalid;
			loRd = `Invalid;
        end
        else begin // I instruction
            //jAddr = `Zero;
            //jCe = `Invalid;
            case (inst_op)
                `Rinst:begin
                    case (func)
                        `ADD:begin
                            op = `ADD;
                            regaRd = `Valid;
                            regaAddr = inst[25:21];
                            regbRd = `Valid;
                            regbAddr = inst[20:16];
                            regcWr = `Valid;
                            regcAddr = inst[15:11];
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end
                        `SUB:begin
                            op = `SUB;
                            regaRd = `Valid;
                            regaAddr = inst[25:21];
                            regbRd = `Valid;
                            regbAddr = inst[20:16];
                            regcWr = `Valid;
                            regcAddr = inst[15:11];
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end
                        `AND:begin
                            op = `AND;
                            regaRd = `Valid;
                            regaAddr = inst[25:21];
                            regbRd = `Valid;
                            regbAddr = inst[20:16];
                            regcWr = `Valid;
                            regcAddr = inst[15:11];
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end
                        `OR:begin
                            op = `OR;
                            regaRd = `Valid;
                            regaAddr = inst[25:21];
                            regbRd = `Valid;
                            regbAddr = inst[20:16];
                            regcWr = `Valid;
                            regcAddr = inst[15:11];
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end
                        `XOR:begin
                            op = `XOR;
                            regaRd = `Valid;
                            regaAddr = inst[25:21];
                            regbRd = `Valid;
                            regbAddr = inst[20:16];
                            regcWr = `Valid;
                            regcAddr = inst[15:11];
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end

                        `SLL:begin
                            op = `SLL;
                            regaRd = `Valid;
                            regaAddr = inst[20:16];
                            regbRd = `Valid;
                            regbAddr = inst[10:6];
                            regcWr = `Valid;
                            regcAddr = inst[15:11];
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end
                        `SRL:begin
                            op = `SRL;
                            regaRd = `Valid;
                            regaAddr = inst[20:16];
                            regbRd = `Valid;
                            regbAddr = inst[10:6];
                            regcWr = `Valid;
                            regcAddr = inst[15:11];
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end
                        `SRA:begin
                            op = `SRA;
                            regaRd = `Valid;
                            regaAddr = inst[20:16];
                            regbRd = `Valid;
                            regbAddr = inst[10:6];
                            regcWr = `Valid;
                            regcAddr = inst[15:11];
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end

                        `JR:begin
                            op = `JR;
                            regaRd = `Valid;
                            regaAddr = inst[25:21];
                            regbRd = `Invalid;
                            regbAddr = `Zero;
                            regcWr = `Invalid;
                            regcAddr = `Zero;
                            jAddr = regaData_i;
                            jCe = `Valid;
                            imm = npc;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end
 						`SLT:begin
                            op = `SLT;
                            regaRd = `Valid;
                            regaAddr = inst[25:21];
                            regbRd = `Valid;
                            regbAddr = inst[20:16];
                            regcWr = `Valid;
                            regcAddr = inst[15:11];
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        
                        end
                        `JALR:begin
                            op = `JALR;
                            regaRd = `Valid;
                            regaAddr = inst[25:21];
                            regbRd = `Invalid;
                            regbAddr = `Zero;
                            regcWr = `Valid;
                            regcAddr = 5'b11111;
                            jAddr = regaData_i;
                            jCe = `Valid;
                            imm = npc;
							hiRd = `Invalid;
							loRd = `Invalid;

                        end
                        `MULT:begin
                            op = `MULT;
                            regaRd = `Valid;
                            regaAddr = inst[25:21];
                            regbRd = `Valid;
                            regbAddr = inst[20:16];
                            regcWr = `Invalid;
                            regcAddr = `Zero;
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;

                        end
                        `MULTU:begin
                            op = `MULTU;
                            regaRd = `Valid;
                            regaAddr = inst[25:21];
                            regbRd = `Valid;
                            regbAddr = inst[20:16];
                            regcWr = `Invalid;
                            regcAddr = `Zero;
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end
                        `DIV:begin
                            op = `DIV;
                            regaRd = `Valid;
                            regaAddr = inst[25:21];
                            regbRd = `Valid;
                            regbAddr = inst[20:16];
                            regcWr = `Invalid;
                            regcAddr = `Zero;
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end
                        `DIVU:begin
                            op = `DIVU;
                            regaRd = `Valid;
                            regaAddr = inst[25:21];
                            regbRd = `Valid;
                            regbAddr = inst[20:16];
                            regcWr = `Invalid;
                            regcAddr = `Zero;
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end
                        `MFHI:begin
                            op = `MFHI;
                            regaRd = `Invalid;
                            regaAddr = `Zero;
                            regbRd = `Invalid;
                            regbAddr = `Zero;
                            regcWr = `Valid;
                            regcAddr = inst[15:11];
                            hiRd = `Valid;
                            imm = regaData_i;
							hiRd = `Valid;
							loRd = `Invalid;
                        end
                        `MFLO:begin
                            op = `MFLO;
                            regaRd = `Invalid;
                            regaAddr = `Zero;
                            regbRd = `Invalid;
                            regbAddr = `Zero;
                            regcWr = `Valid;
                            regcAddr = inst[15:11];
                            loRd = `Valid;
                            imm = regbData_i;
							hiRd = `Invalid;
							loRd = `Valid;
                        end
                        `MTHI:begin
                            op = `MTHI;
                            regaRd = `Valid;
                            regaAddr = inst[25:21];
                            regbRd = `Invalid;
                            regbAddr = `Zero;
                            regcWr = `Valid;
                            regcAddr = `Zero;
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end
                        `MTLO:begin
                            op = `MTLO;
                            regaRd = `Valid;
                            regaAddr = inst[25:21];
                            regbRd = `Invalid;
                            regbAddr = `Zero;
                            regcWr = `Valid;
                            regcAddr = `Zero;
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end
                        default:begin
                            op = `Zero;
                            regaRd = `Invalid;
                            regaAddr = `Zero;
                            regbRd = `Invalid;
                            regbAddr = `Zero;
                            regcWr = `Invalid;
                            regcAddr = `Zero;
                            imm = `Zero;
							hiRd = `Invalid;
							loRd = `Invalid;
                        end
                    endcase
                end
                `ADDI:begin
                    op = `ADDI;
                    regaRd = `Valid;
                    regaAddr = inst[25:21];
                    regbRd = `Invalid;
                    regbAddr = `Zero;
                    regcWr = `Valid;
                    regcAddr = inst[20:16];
                    imm = {{16{inst[15]}},inst[15:0]};
					hiRd = `Invalid;
					loRd = `Invalid;
                end
                `ANDI:begin
                    op = `ANDI;
                    regaRd = `Valid;
                    regaAddr = inst[25:21];
                    regbRd = `Invalid;
                    regbAddr = `Zero;
                    regcWr = `Valid;
                    regcAddr = inst[20:16];
                    imm = {16'h0,inst[15:0]};
					hiRd = `Invalid;
					loRd = `Invalid;
                end
                `ORI:begin
                    op = `ORI;
                    regaRd = `Valid;
                    regaAddr = inst[25:21];
                    regbRd = `Invalid;
                    regbAddr = `Zero;
                    regcWr = `Valid;
                    regcAddr = inst[20:16];
                    imm = {16'h0,inst[15:0]};
					hiRd = `Invalid;
					loRd = `Invalid;
                end
                `XORI:begin
                    op = `XORI;
                    regaRd = `Valid;
                    regaAddr = inst[25:21];
                    regbRd = `Invalid;
                    regbAddr = `Zero;
                    regcWr = `Valid;
                    regcAddr = inst[20:16];
                    imm = {16'h0,inst[15:0]};
					hiRd = `Invalid;
					loRd = `Invalid;
                end

                `LW:begin   //write reg
                    op = `LW;
                    regaRd = `Valid;
                    regaAddr = inst[25:21];
                    regbRd = `Invalid;
                    regbAddr = `Zero;
                    regcWr = `Valid;
                    regcAddr = inst[20:16];
                    imm = {{16{inst[15]}},inst[15:0]};
					hiRd = `Invalid;
					loRd = `Invalid;
                end
                `SW:begin   //read from ram
                    op = `SW;
                    regaRd = `Valid;
                    regaAddr = inst[25:21];
                    regbRd = `Valid;
                    regbAddr = inst[20:16];
                    regcWr = `Invalid;
                    regcAddr = `Zero;
                    imm = {{16{inst[15]}},inst[15:0]};
					hiRd = `Invalid;
					loRd = `Invalid;
                end

                `BEQ:begin
                    op = `BEQ;
                    regaRd = `Valid;
                    regaAddr = inst[25:21];
                    regbRd = `Valid;
                    regbAddr = inst[20:16];
                    regcWr = `Invalid;
                    regcAddr = `Zero;
                    if(regaData_i == regbData_i)
                        jAddr = {{14{inst[15]}},inst[15:0],2'b00}+npc;
                    else jAddr = npc;
                    jCe = `Valid;
                    imm = `Zero;
					hiRd = `Invalid;
					loRd = `Invalid;
                end
                `BNE:begin
                    op = `BNE;
                    regaRd = `Valid;
                    regaAddr = inst[25:21];
                    regbRd = `Valid;
                    regbAddr = inst[20:16];
                    regcWr = `Invalid;
                    regcAddr = `Zero;
                    if(regaData_i != regbData_i)
                        jAddr = {{14{inst[15]}},inst[15:0],2'b00}+npc;
                    else jAddr = npc;
                    jCe = `Valid;
                    imm = `Zero;
					hiRd = `Invalid;
					loRd = `Invalid;
                end
				`BGTZ:begin
                    op = `BGTZ;
                    regaRd = `Valid;
                    regaAddr = inst[25:21];
                    regbRd = `Invalid;
                    regbAddr = `Zero;
                    regcWr = `Invalid;
                    regcAddr = `Zero;
                    if($signed(regaData_i)> 0)
                        jAddr = {{14{inst[15]}},inst[15:0],2'b00}+npc;
                    else
                        jAddr = npc;
                    jCe = `Valid;
                    imm = `Zero;
					hiRd = `Invalid;
					loRd = `Invalid;
                end
                `BLTZ:begin
                    op = `BLTZ;
                    regaRd = `Valid;
                    regaAddr = inst[25:21];
                    regbRd = `Invalid;
                    regbAddr = `Zero;
                    regcWr = `Invalid;
                    regcAddr = `Zero;
                    if($signed(regaData_i) < 0)
			//			 jAddr = npc;
                        jAddr = {{14{inst[15]}},inst[15:0],2'b00}+npc;
                    else
                       jAddr = npc;
 		//				jAddr = {{14{inst[15]}},inst[15:0],2'b00}+npc;
                    jCe = `Valid;
                    imm = `Zero;
					hiRd = `Invalid;
					loRd = `Invalid;
                end

                `LUI:begin
                    op = `LUI;
                    regaRd = `Invalid;
                    regaAddr = `Zero;
                    regbRd = `Invalid;
                    regbAddr = `Zero;
                    regcWr = `Valid;
                    regcAddr = inst[20:16];
                    imm = {16'h0,inst[15:0]};
					hiRd = `Invalid;
					loRd = `Invalid;
                end
                `J:begin
                    op = `J;
                    regaRd = `Invalid;
                    regaAddr = `Zero;
                    regbRd = `Invalid;
                    regbAddr = `Zero;
                    regcWr = `Invalid;
                    regcAddr = `Zero;
                    jAddr = {{npc[31:28]},{inst[25:0]},2'b00};
                    jCe = `Valid;
                    imm = `Zero; 
					hiRd = `Invalid;
					loRd = `Invalid;
                end
                `JAL:begin
                    op = `JAL;
                    regaRd = `Invalid;
                    regaAddr = `Zero;
                    regbRd = `Invalid;
                    regbAddr = `Zero;
                    regcWr = `Valid;
                    regcAddr = 5'b11111;
                    jAddr = {npc[31:28],inst[25:0],2'b00};
                    jCe = `Valid;
                    imm = npc; 
					hiRd = `Invalid;
					loRd = `Invalid;
                end
                `BGTZ:begin
                    op = `BGTZ;
                    regaRd = `Valid;
                    regaAddr = inst[25:21];
                    regbRd = `Invalid;
                    regbAddr = `Zero;
                    regcWr = `Invalid;
                    regcAddr = `Zero;
                    if(regaData_i > 0)
                        jAddr = {{14{inst[15]}},inst[15:0],2'b00}+npc;
                    else
                        jAddr = npc;
                    jCe = `Valid;
                    imm = `Zero;
                end
                `BLTZ:begin
                    op = `BLTZ;
                    regaRd = `Valid;
                    regaAddr = inst[25:21];
                    regbRd = `Invalid;
                    regbAddr = `Zero;
                    regcWr = `Invalid;
                    regcAddr = `Zero;
                    if(regaData_i < 0)
                        jAddr = {{14{inst[15]}},inst[15:0],2'b00}+npc;
                    else
                        jAddr = npc;
                    jCe = `Valid;
                    imm = `Zero;
                end
                default: begin
                    op = `Zero;
                    regaRd = `Invalid;
                    regaAddr = `Zero;
                    regbRd = `Invalid;
                    regbAddr = `Zero;
                    regcWr = `Invalid;
                    regcAddr = `Zero;
                    imm = `Zero;
					hiRd = `Invalid;
					loRd = `Invalid;
                end
            endcase
        end

    end



    always@(*)begin // rega get data
        if(rst == `Valid)   regaData = `Zero;
        else if(op == `LW || op == `SW)
        begin
           regaData = regaData_i + imm;
       //    regaData = {regaData[29:0],2'b00}; 
        end
        else if(regaRd == `Valid || hiRd == `Valid)    regaData = regaData_i;
        else    regaData = imm;

    end

    always@(*)begin // regb get data
        if(rst == `Valid)   regbData = `Zero;
        else if(regbRd == `Valid || loRd == `Valid)    regbData = regbData_i;
        else regbData = imm;
    end

endmodule

